#include "MulticastServer.h"

/*-----------------------------------------------------------------------------------------
--
--	FUNCTION: MulticastServer
--
--	Date: March 25, 2010
--
--	REVISIONS (Date and Description):
--
--	DESIGNER: Brad Paugh, Renz Barron
--
--	PROGRAMMER: Brad Paugh, Renz Barron
--
--  INTERFACE: MulticastServer::MulticastServer(Playlist * thePlaylist)
--
--      Playlist * thePlaylist: The Playlist object with which to initialize the server
--                              to.
--
--  RETURNS: N/A
--
--	NOTES: Initialize the Winsock DLL, create socket, bind to a port, and assign an
--         address. This server is also added to the Playlist's list to observe.
--
-----------------------------------------------------------------------------------------*/
MulticastServer::MulticastServer(Playlist * thePlaylist) : playlist(thePlaylist)
{
    WORD		wVersionRequested = MAKEWORD(2,2);
    
	WSADATA		WSAdata;
   
	WSAStartup(wVersionRequested, &WSAdata);

    sock.Create("UDP");
    sock.setMulticastServer("239.255.255.255", MCPORT);

    playlist->addObserver(this);
    
	microphone = false;
	
	totalBytesRead = 0;
}

/*-----------------------------------------------------------------------------------------
--
--	FUNCTION: sendPacket
--
--	Date: March 25, 2010
--
--	REVISIONS (Date and Description):
--
--	DESIGNER: Brad Paugh
--
--	PROGRAMMER: Brad Paugh
--
--  INTERFACE: void MulticastServer::sendPacket(char* packet, int packetSize)
--
--      char* packet: The packet to send.
--      int packetSize: The size of the packet in bytes.
--
--  RETURNS: void
--
--	NOTES: Wrapper function for the 'SendTo' function.
--
-----------------------------------------------------------------------------------------*/
void MulticastServer::sendPacket(char* packet, int packetSize)
{
    sock.SendTo(packet, packetSize);
}

/*--------------------------------------------------------------------------------------------
--
--	FUNCTION: runServer
--
--	Date: March 25, 2010
--
--	REVISIONS (Date and Description):
--
--	DESIGNER: Brad Paugh, Erick Ribeiro
--
--	PROGRAMMER: Brad Paugh
--
--  INTERFACE: void MulticastServer::runServer()
--
--  RETURNS: void
--
--	NOTES: Calls the inherited method of the 'Runnable' class to create a thread to handle
--         the main functions of the server.
--
--------------------------------------------------------------------------------------------*/
void MulticastServer::runServer()
{
    startRunning();
}

/*-----------------------------------------------------------------------------------------
--
--	FUNCTION: toggleMic
--
--	Date: March 25, 2010
--
--	REVISIONS (Date and Description):
--
--	DESIGNER: Brad Paugh
--
--	PROGRAMMER: Brad Paugh
--
--  INTERFACE: void MulticastServer::toggleMic (bool on)
--
--      bool on: Flag to indicate whether the microphone mode is enabled.
--
--  RETURNS: void
--
--	NOTES: Toggles the microphone mode of the program on or off.
--
-----------------------------------------------------------------------------------------*/
void MulticastServer::toggleMic (bool on)
{
    microphone = on;
}

/*-------------------------------------------------------------------------------------------------
--
--	FUNCTION: run
--
--	Date: March 27, 2010
--
--	REVISIONS (Date and Description):
--
--	DESIGNER: Brad Paugh
--
--	PROGRAMMER: Brad Paugh
--
--  INTERFACE: void MulticastServer::run()
--
--  RETURNS: void
--
--	NOTES: Main functions of the multicast server. 
--
--         If microphone is enabled, function 'runPlaylist' is executed, otherwise 'recordMic'
--         is called. Both functions are explained in their own headers.
--
-------------------------------------------------------------------------------------------------*/
void MulticastServer::run()
{
    while(1)
    {
        if(!microphone)
        {
            runPlaylist();
        }

        else
        {
            recordMic();
        }
    }
}

/*-------------------------------------------------------------------------------------------
--
--	FUNCTION: notify
--
--	Date: March 25, 2010
--
--	REVISIONS (Date and Description):
--
--	DESIGNER: Brad Paugh, Erick Ribeiro
--
--	PROGRAMMER: Brad Paugh
--
--  INTERFACE: void MulticastServer::notify (Observable * obj, int eventCode)
--
--      Observable * obj: The object to notify when an event occurs.
--      int eventCode: What event occured.
--
--  RETURNS: void
--
--	NOTES: Method inherited from the Observer class to notify all objects in the server's
--         list when an event occurs.
--
-------------------------------------------------------------------------------------------*/
void MulticastServer::notify (Observable * obj, int eventCode)
{
    if (obj == playlist && eventCode == Playlist::SongAdded)
    {
        if (!isRunning())
		{
            runServer();
		}
    }
}

/*-------------------------------------------------------------------------------------------------
--
--	FUNCTION: runPlaylist
--
--	Date: April 5, 2010
--
--	REVISIONS (Date and Description):
--
--	DESIGNER: Brad Paugh
--
--	PROGRAMMER: Brad Paugh
--
--  INTERFACE: void MulticastServer::runPlaylist()
--
--  RETURNS: void
--
--	NOTES: Main functions of the multicast server - Playlist mode enabled 
--
--         If the playlist mode is enabled, the server checks if there are any songs in the
--         Playlist. The song data is then extracted and sent to all connected clients. There
--         is a delay calculated in the code below to synchronize the sending of packets so that
--         the server doesn't send the packets too fast.
--
-------------------------------------------------------------------------------------------------*/
void MulticastServer::runPlaylist()
{
	while (playlist->hasNext())
    {
        int bytesRead = 0;
        char* buffer = (char*)malloc(BUFSIZE);
        char* data = (char*)malloc(BUFSIZE - HEADERSIZE);
        int millisecs;
        FILE* fp;

		if (totalBytesRead > 0)
		{
			fp = fopen(fileName.c_str(),"rb");
			if(!fp)
			{
				printf("File not found");
				exit(1);
			}
			fseek(fp, totalBytesRead, SEEK_SET);
		}
		else
		{
			as = new AudioSystem();
			fileName = playlist->next()->getPath();
			fp = fopen(fileName.c_str(),"rb");
			if(!fp)
			{
				printf("File not found");
				exit(1);
			}
			header = as->extractHeaderInfo(fp);
			totalBytesRead = totalBytesRead + 23;
		}
        while(1)
        {
            if (microphone)
			{
				fclose(fp);
				return;
			}
            bytesRead = fread(data, 1, BUFSIZE-HEADERSIZE, fp);
			totalBytesRead = totalBytesRead + bytesRead;
            if (bytesRead == 0)
			{
				totalBytesRead = 0;
				fclose(fp);
                return;
			}

            memcpy(buffer, header, HEADERSIZE);
            memcpy(&buffer[HEADERSIZE], data, bytesRead);
            this->sendPacket(buffer, bytesRead+HEADERSIZE);
            millisecs = as->getMsPerPacket(bytesRead+HEADERSIZE);
			//we want to send the next packet when 97% of the packet is played
            millisecs = millisecs*.97;
            Sleep(millisecs);
        }
    }
}

/*-------------------------------------------------------------------------------------------------
--
--	FUNCTION: recordMic
--
--	Date: April 5, 2010
--
--	REVISIONS (Date and Description):
--
--	DESIGNER: Brad Paugh
--
--	PROGRAMMER: Brad Paugh
--
--  INTERFACE: void MulticastServer::recordMic()
--
--  RETURNS: void
--
--	NOTES: Main functions of the multicast server - Microphone mode enabled 
--
--         If microphone is enabled, it receives data and transfers it to the Record System 
--         object to handle the processing of that data. The data returned by the Record System 
--         is then sent by this server to all connected clients.
--
-------------------------------------------------------------------------------------------------*/
void MulticastServer::recordMic()
{
	RecordSystem* rs = new RecordSystem();
	int millisecs;

    rs->startRecording();
	millisecs = rs->getMsPerPacket(BUFSIZE);
	//sleep for one packet time so we are not sending a packet that is being recorded
	Sleep(millisecs);
    char* buffer = (char*)malloc(BUFSIZE);
    memset(buffer, '0', BUFSIZE);

    while(1)
    {
		//we want to send the next packet when 97% of the packet is played
		Sleep(millisecs*.97);
        if (!microphone)
		{
			rs->close();
            return;
		}
        rs->getNextBuffer(buffer);
		this->sendPacket(buffer, BUFSIZE);
    }
}